﻿using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Thrift.Transport;

namespace Thrift.Utility.Utility
{
    public class ProxyInterceptor:IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            #region 重置入参
            object[] args = invocation.Arguments;
            string methodName = invocation.Method.Name;
            string serviceName = invocation.Method.ReflectedType.FullName;
            StandRequest<string> request = BuildRequest(methodName, string.Empty);
            if (args != null && args.Count() > 0 && args[0]!=null)
            {
                string arg = args[0].ToString();
                if(!string.IsNullOrWhiteSpace(arg))
                {
                    request = BuildRequest(methodName, arg);
                }
            }
            invocation.SetArgumentValue(0, SerializeHelper.JsonSerialize3(request));
            #endregion

            #region 错误处理
            try
            {
                invocation.Proceed();
            }
            catch (IOException idEx)
            {
                throw new ThriftException(ThriftException.ExceptionType.Timeout, string.Format("请求超时。\r请求服务：{0}\r请求方法：{1}\r请求数据：{2}", serviceName, methodName, SerializeHelper.JsonSerialize3(request)));
            }
            catch (TTransportException transEx)
            {
                throw new ThriftException(ThriftException.ExceptionType.ServerUnkown, string.Format("服务端未处理系统异常。\r请求服务：{0}\r请求方法：{1}\r请求数据：{2}", serviceName, methodName, SerializeHelper.JsonSerialize3(request)));
            }
            catch (Exception ex)
            {
                throw ex;
            }

            StandResponse<string> response = null;
            object returnValue = invocation.ReturnValue;
            if(returnValue!=null)
            {
                response = SerializeHelper.JsonDeserialize3<StandResponse<string>>(returnValue.ToString());
                if (response != null && response.Code == "-1")
                {
                    throw new ThriftException(ThriftException.ExceptionType.InvalidRequestPara, string.Format("请求数据异常。\r请求服务：{0}\r请求方法：{1}\r请求数据：{2}", serviceName, methodName, SerializeHelper.JsonSerialize3(request)));
                }
                if (response != null && response.Code == "-2")
                {
                    throw new ThriftException(ThriftException.ExceptionType.ServerCaptured, string.Format("服务端系统异常。\r请求服务：{0}\r请求方法：{1}\r请求数据：{2}", serviceName, methodName, SerializeHelper.JsonSerialize3(request)));
                }
            }
            #endregion

            #region 修改返回值
            if (response!=null)
            {
                invocation.ReturnValue = response.Data;
            }
            #endregion
        }

        private StandRequest<string> BuildRequest(string methodName, string request)
        {
            Func<string> getIP = () =>
            {
                string ip = string.Empty;
                IPAddress[] address = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
                if (address != null)
                {
                    foreach (IPAddress addr in address)
                    {
                        //过滤IPv6的地址信息
                        if (addr.ToString().Length <= 16 && addr.ToString().Length > 5)
                        {
                            ip = addr.ToString();
                            break;
                        }
                    }
                }
                return ip;
            };
            Func<string> getRequestUrl = () =>
            {
                string result;
                try
                {
                    if (HttpContext.Current != null && HttpContext.Current.Request != null)
                    {
                        result = HttpContext.Current.Request.Url.AbsoluteUri;
                    }
                    else if (OperationContext.Current != null && OperationContext.Current.RequestContext != null && OperationContext.Current.RequestContext.RequestMessage != null && OperationContext.Current.RequestContext.RequestMessage.Headers != null)
                    {
                        result = OperationContext.Current.RequestContext.RequestMessage.Headers.To.AbsoluteUri;
                    }
                    else
                    {
                        result = string.Empty;
                    }
                }
                catch
                {
                    result = string.Empty;
                }
                return result;
            };
            Func<string> getUserRequestIP = () =>
            {
                string result;
                try
                {
                    if (HttpContext.Current != null && HttpContext.Current.Request != null)
                    {
                        result = HttpContext.Current.Request.UserHostAddress;
                    }
                    else
                    {
                        if (OperationContext.Current != null)
                        {
                            RemoteEndpointMessageProperty endpointProperty = OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
                            if (endpointProperty != null)
                            {
                                result = endpointProperty.Address;
                                return result;
                            }
                        }
                        result = string.Empty;
                    }
                }
                catch
                {
                    result = string.Empty;
                }
                return result;
            };

            StandRequest<string> q = new StandRequest<string>();
            q.HostName = Dns.GetHostName();
            q.IP = getIP();
            q.RequestUrl = getRequestUrl();
            q.UserRequestIP = getUserRequestIP();
            q.RequestTime = DateTime.UtcNow;
            q.TimeStamp = (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds.ToString();
            q.Sign = q.SignTimestamp(q.TimeStamp);
            q.MethodName = methodName;
            q.Data = request;
            return q;
        }
    }
}
